﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System.Collections.Generic;
using System.Linq;

using ScrumTable.Common;
using ScrumTable.Common.Collections;

using CacheWorkItemBucket = ScrumTable.DL.Data.Generic.Cache.CacheElementListEntryBucket<ScrumTable.DL.Data.Generic.Cache.CacheWorkItem>;

#endregion


namespace ScrumTable.DL.Data.Generic.Cache
{
    /// <summary>
    /// Represents a cache for optimized access work items by their unique id. This
    /// is important during the import of server side changes.
    /// </summary>
    internal class CacheWorkItemHierarchy : IEnumerable<KeyValuePair<ValueChain<string>, CacheWorkItemBucket>>
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private readonly IDictionary<ValueChain<string>, IDictionary<string, CacheWorkItemBucket>> _workItemCache
            = new Dictionary<ValueChain<string>, IDictionary<string, CacheWorkItemBucket>>();

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the number of elements stored in the list.
        /// </summary>
        internal int Count
        {
            get { return _workItemCache.Sum(keyValuePair => keyValuePair.Value.Count); }
        }

        /// <summary>
        /// Gets the workitem buckets by its parent id chain.
        /// </summary>
        internal CacheWorkItemBucket this[ValueChain<string> parentIdChain, string childId]
        {
            get { return this[parentIdChain][childId]; }
            set { this[parentIdChain][childId] = value; }
        }

        private IDictionary<string, CacheWorkItemBucket> this[ValueChain<string> parentIdChain]
        {
            get
            {
                PreCondition.AssertNotNull(parentIdChain, "parentIdChain");

                if (!Contains(parentIdChain))
                    _workItemCache[parentIdChain] = new Dictionary<string, CacheWorkItemBucket>();
                return _workItemCache[parentIdChain];
            }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        internal CacheWorkItemHierarchy()
        {
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Returns an enumerator that iterates through the collection and returns the bucket with its unique id.
        /// </summary>
        public IEnumerator<KeyValuePair<ValueChain<string>, CacheWorkItemBucket>> GetEnumerator()
        {
            return (from cacheWorkItemParent in _workItemCache
                    from keyValuePair in cacheWorkItemParent.Value
                    select new KeyValuePair<ValueChain<string>, CacheWorkItemBucket>(
                        new ValueChain<string>(cacheWorkItemParent.Key, keyValuePair.Key),
                        keyValuePair.Value)).GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through the collection and returns the bucket with its unique id.
        /// </summary>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return ((CacheWorkItemHierarchy)this).GetEnumerator();
        }


        /// <summary>
        /// Returns true, if the current list contains a value with the given parentIdChain.
        /// </summary>
        /// <param name="parentIdChain">Id of the element to check.</param>
        internal bool Contains(ValueChain<string> parentIdChain)
        {
            PreCondition.AssertNotNull(parentIdChain, "parentIdChain");

            return _workItemCache.ContainsKey(parentIdChain);
        }

        /// <summary>
        /// Returns true, if the current list contains a value with the given parentIdChain.
        /// </summary>
        /// <param name="parentIdChain">Parent id of the element to check.</param>
        /// <param name="childId">Id of the element to check.</param>
        internal bool Contains(ValueChain<string> parentIdChain, string childId)
        {
            PreCondition.AssertNotNull(parentIdChain, "parentIdChain");

            return _workItemCache.ContainsKey(parentIdChain) && this[parentIdChain].ContainsKey(childId);
        }

        internal void Remove(ValueChain<string> parentChain, string uniqueIdToRemove)
        {
            if (Contains(parentChain))
            {
                var childElements = this[parentChain];
                if (childElements.Count > 0)
                {
                    childElements.Remove(uniqueIdToRemove);
                }
                if (childElements.Count == 0)
                {
                    _workItemCache.Remove(parentChain);
                }
            }
        }

        internal IList<ValueChain<string>> GetChildChains(ValueChain<string> parentChain)
        {
            return (from storage in _workItemCache
                    from storageItem in storage.Value
                    let storageItemKey = new ValueChain<string>(storage.Key, storageItem.Key)
                    where storageItemKey.IsBelowChain(parentChain)
                    select storageItemKey).ToList();
        }

        internal IEnumerable<KeyValuePair<string, CacheWorkItemBucket>> GetChildren(ValueChain<string> parentChain)
        {
            return this[parentChain];
        }

        #endregion
    }
}
